#include "Command.h"
#include "RFCDetails.h"
#include <string.h>

Command::Command()
{
	this -> _packet.opCode = 0;
	this ->	_numOfParams = 0;
	this -> _packet.params = 0;
}

Command::Command(byte* networkBuffer)
{
	this -> _packet.opCode = networkBuffer[OPCODE];
	this ->_packet.params = (networkBuffer + PARAMS);

	int opCodePrams[] = {MOVE_MOUSE_INT_VALUES}; 
	this ->	_numOfParams = opCodePrams[this -> _packet.opCode - 1];
}

Command::Command(unsigned int opCode)
{
	this -> _packet.opCode = opCode;
	this ->	_numOfParams = 0;
	this -> _packet.params = 0;
}

byte* Command::Generate()
{
   int i = 0;
   this -> _packet.size_t = sizeof(this ->_packet);
   byte buffer[MAX_PACKET_SIZE] = {0};

   //IMPORTENET!! 
   //RFCDetails hard coded , one byte for size and opcode.
   //TODO: handle RFCDetails.
   buffer[i] = this ->_packet.size_t; // assuming size_t is 1 byte only.
   i += SIZEOFPACKET_LEN;

   buffer[i] = this -> _packet.opCode; // assuming opCode is 1 byte only.
   i += OPCODE_LEN;

   memcpy(buffer + i, (void*) &(this ->_packet.params), sizeof(this ->_packet.params));
   i += sizeof(this ->_packet.params);

   return buffer;
}

void Command::SetOpCode(const unsigned int opCode)
{
	if(this ->_packet.params != 0)
	{
		this ->_packet.params = 0;
	}
	this -> _packet.opCode = opCode;
}

void Command::AddParams(byte* param , ...)
{
	byte bufferParams[MAX_PACKET_SIZE] = {0};
	int curPos = 0; //last end value at buffer params.
	va_list argptr; // pointer to optional arguments
	if(this -> _packet.opCode == 0)
	{
		throw NOCOMMANDSET; // opcode should set first
	}

	va_start(argptr , param);

	switch (this -> _packet.opCode)
	{
		//Mouse move , gets two int arguments.
		case 0x01: {
					for(int i = 0 ; i < MOVE_MOUSE_INT_VALUES ; i++)
					{
						try
						{
							memcpy(bufferParams + curPos, &param , sizeof(int));
							curPos += sizeof(int);
							param = reinterpret_cast<byte*>(va_arg(argptr , void*));
						}
						catch(...)
						{
							throw INVALIDPARAM;
						}
					}
					this -> _packet.params = bufferParams;
					this -> _numOfParams = MOVE_MOUSE_INT_VALUES;
					break;
				   }
		default: break;
	}

	va_end(argptr);
}

byte Command::GetOpCode()
{
	return this ->_packet.opCode;
}

byte* Command::GetParams()
{
	return this ->_packet.params;
}

int Command::GetNumOfParams()
{
	return this ->_numOfParams;
}

unsigned int Command::GetPacketLegnth;
{
	return this ->_packet.size_t;
}

Command :: ~Command()
{
}
